/**
 * Created by XianTao on 2015/8/6
 * <p/>
 * Copyright (c) 2015-2015
 * Apache License
 * Version 2.0, January 2004
 * http://www.apache.org/licenses/
 */
package org.lego.wechat.base.msg;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.lego.wechat.base.msg.in.*;
import org.lego.wechat.base.msg.in.event.InFollowEvent;
import org.lego.wechat.base.msg.in.event.InLocationEvent;
import org.lego.wechat.base.msg.in.event.InMenuEvent;
import org.springframework.util.StringUtils;

/**
 * 输入消息解析器
 */
public class InMsgParser {
    private InMsgParser() {
    }

    /**
     * 从xml中解析出各类消息和事件
     */
    public static InMsg parser(String xml, Integer agentId) {
        try {
            return doParse(xml, agentId);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }

    private static InMsg doParse(String xml, Integer agentId) throws DocumentException {
        Document doc = DocumentHelper.parseText(xml);
        Element root = doc.getRootElement();
        String toUserName = root.elementText("ToUserName");
        String fromUserName = root.elementText("FromUserName");
        Integer createTime = Integer.parseInt(root.elementText("CreateTime"));
        String msgType = root.elementText("MsgType");

        String tempAgentId = root.elementText("AgentID");
        if (StringUtils.hasText(tempAgentId)) {
            agentId = Integer.parseInt(tempAgentId);
        }

        String msgIdStr = root.elementText("MsgId");
        Long msgId = null;
        if (StringUtils.hasText(msgIdStr)) {
            msgId = Long.parseLong(msgIdStr);
        }
        if ("text".equals(msgType)) {
            return parseInTextMsg(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        } else if ("image".equals(msgType)) {
            return parseInImageMsg(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        } else if ("voice".equals(msgType)) {
            return parseInVoiceMsg(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        } else if ("shortvideo".equals(msgType) || "video".equals(msgType)) {
            return parseInShortVideoMsg(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        } else if ("event".equals(msgType)) {
            return parseInEvent(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        } else if ("location".equals(msgType)) {
            return parseInLocationMsg(root, toUserName, fromUserName, createTime, msgType, agentId, msgId);
        }
        throw new RuntimeException("无法识别的消息类型 " + msgType + "，请查阅微信公众平台开发文档");
    }

    private static InMsg parseInTextMsg(Element root, String toUserName, String fromUserName, Integer createTime,
                                        String msgType, Integer agentId, Long msgId) {
        InTextMsg msg = new InTextMsg(toUserName, fromUserName, createTime, msgType, agentId, msgId);
        msg.setContent(root.elementText("Content"));
        return msg;
    }

    private static InMsg parseInImageMsg(Element root, String toUserName, String fromUserName, Integer createTime,
                                         String msgType, Integer agentId, Long msgId) {
        InImageMsg msg = new InImageMsg(toUserName, fromUserName, createTime, msgType, agentId, msgId);
        msg.setPicUrl(root.elementText("PicUrl"));
        msg.setMediaId(root.elementText("MediaId"));
        return msg;
    }

    private static InMsg parseInVoiceMsg(Element root, String toUserName, String fromUserName, Integer createTime,
                                         String msgType, Integer agentId, Long msgId) {
        InVoiceMsg msg = new InVoiceMsg(toUserName, fromUserName, createTime, msgType, agentId, msgId);
        msg.setFormat(root.elementText("Format"));
        msg.setMediaId(root.elementText("MediaId"));
        msg.setRecognition(root.elementText("Recognition"));
        return msg;
    }

    private static InMsg parseInShortVideoMsg(Element root, String toUserName, String fromUserName, Integer createTime,
                                              String msgType, Integer agentId, Long msgId) {
        InShortVideoMsg msg = new InShortVideoMsg(toUserName, fromUserName, createTime, msgType, agentId, msgId);
        msg.setMediaId(root.elementText("MediaId"));
        msg.setThumbMediaId(root.elementText("ThumbMediaId"));
        return msg;
    }

    private static InMsg parseInEvent(Element root, String toUserName, String fromUserName, Integer createTime,
                                      String msgType, Integer agentId, Long msgId) {
        String event = root.elementText("Event");
        String eventKey = root.elementText("EventKey");
        // 关注/取消关注事件（包括二维码扫描关注，二维码扫描关注事件与扫描带参数二维码事件是两回事）
        if ((InFollowEvent.EVENT_INFOLLOW_SUBSCRIBE.equals(event)
                || InFollowEvent.EVENT_INFOLLOW_UNSUBSCRIBE.equals(event)) && StringUtils.isEmpty(eventKey)) {
            return new InFollowEvent(toUserName, fromUserName, createTime, msgType, event, agentId, msgId);
        }
        if (InMenuEvent.EVENT_INMENU_CLICK.equalsIgnoreCase(event)
                || InMenuEvent.EVENT_INMENU_VIEW.equalsIgnoreCase(event)
                || InMenuEvent.EVENT_INMENU_PIC_PHOTO_OR_ALBUM.equals(event)
                || InMenuEvent.EVENT_INMENU_PIC_SYSPHOTO.equals(event)
                || InMenuEvent.EVENT_INMENU_PIC_WEIXIN.equals(event)
                || InMenuEvent.EVENT_INMENU_LOCATION_SELECT.equals(event)) {
            InMenuEvent inMenuEvent = new InMenuEvent(toUserName, fromUserName, createTime, msgType, event, agentId, msgId);
            inMenuEvent.setEventKey(eventKey);
            return inMenuEvent;
        }
        if (InLocationEvent.EVENT_LOCATION.equalsIgnoreCase(event)) {
            InLocationEvent inLocationEvent = new InLocationEvent(toUserName, fromUserName, createTime, msgType, event, agentId, msgId);
            inLocationEvent.setLatitude(root.elementText("Latitude"));
            inLocationEvent.setLongitude(root.elementText("Longitude"));
            inLocationEvent.setPrecision(root.elementText("Precision"));
            return inLocationEvent;
        }
        throw new RuntimeException("无法识别的事件类型" + event + "，请查阅微信公众平台开发文档");
    }

    private static InMsg parseInLocationMsg(Element root, String toUserName, String fromUserName, Integer createTime,
                                            String msgType, Integer agentId, Long msgId) {
        InLocationMsg msg = new InLocationMsg(toUserName, fromUserName, createTime, msgType, agentId, msgId);
        msg.setLabel(root.elementText("Label"));
        msg.setLocationX(root.elementText("Location_X"));
        msg.setLocationY(root.elementText("Location_Y"));
        msg.setScale(root.elementText("Scale"));
        return msg;
    }
}
